﻿using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Masuit.Tools.Systems;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Formats.Webp;

namespace Masuit.Tools.Strings
{
	/// <summary>
	/// 画验证码
	/// </summary>
	public static class ValidateCode
	{
		/// <summary>
		/// 生成验证码
		/// </summary>
		/// <param name="length">指定验证码的长度</param>
		/// <returns>验证码字符串</returns>
		public static string CreateValidateCode(int length)
		{
			string ch = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ1234567890@#$%&?";
			byte[] b = new byte[4];
			using var cpt = RandomNumberGenerator.Create();
			cpt.GetBytes(b);
			var r = new Random(BitConverter.ToInt32(b, 0));
			var sb = new StringBuilder();
			for (int i = 0; i < length; i++)
			{
				sb.Append(ch[r.StrictNext(ch.Length)]);
			}

			return sb.ToString();
		}

		/// <summary>
		/// 创建验证码的图片
		/// </summary>
		/// <param name="validateCode">验证码序列</param>
		/// <param name="fontSize">字体大小，默认值28px</param>
		/// <exception cref="Exception">The operation failed.</exception>
		public static PooledMemoryStream CreateValidateGraphic(this string validateCode, int fontSize = 28)
		{
			var fontFamily = SystemFonts.Families.Where(f => new[] { "Consolas", "DejaVu Sans", "KaiTi", "NSimSun", "SimSun", "SimHei", "Microsoft YaHei UI", "Arial" }.Contains(f.Name)).OrderByRandom().FirstOrDefault();
			if (fontFamily == default)
			{
				fontFamily = SystemFonts.Families.OrderByRandom().FirstOrDefault();
			}

			var font = fontFamily.CreateFont(fontSize);
			var measure = TextMeasurer.MeasureSize(validateCode, new TextOptions(font));
			var width = (int)Math.Ceiling(measure.Width + 15);
			var height = (int)Math.Ceiling(measure.Height + 15);
			using var image = new Image<Rgba32>(width, height);

			//生成随机生成器
			Random random = new Random();

			//清空图片背景色
			image.Mutate(g =>
			{
				g.BackgroundColor(Color.White);

				//画图片的干扰线
				for (int i = 0; i < 65; i++)
				{
					int x1 = random.StrictNext(width);
					int x2 = random.StrictNext(width);
					int y1 = random.StrictNext(height);
					int y2 = random.StrictNext(height);
					g.Draw(new SolidPen(new Color(new Rgba32((byte)random.StrictNext(255), (byte)random.StrictNext(255), (byte)random.StrictNext(255))), 1), new Path(new[] { new PointF(x1, y1), new PointF(x2, y2) }));
				}

				//渐变.
				var brush = new LinearGradientBrush(new PointF(0, 0), new PointF(width, height), GradientRepetitionMode.Repeat, new ColorStop(0.5f, Color.Blue), new ColorStop(0.5f, Color.DarkRed));
				g.DrawText(validateCode, font, brush, new PointF(3, 2));

				//画图片的边框线
				g.Draw(Color.Silver, 1, new RectangleF(0, 0, width - 1, height - 1));
			});

			//画图片的前景干扰点
			for (int i = 0; i < 350; i++)
			{
				int x = random.StrictNext(image.Width);
				int y = random.StrictNext(image.Height);
				image[x, y] = new Rgba32(random.StrictNext(255), random.StrictNext(255), random.StrictNext(255));
			}

			//保存图片数据
			var stream = new PooledMemoryStream();
			image.Save(stream, WebpFormat.Instance);
			stream.Position = 0;
			return stream;
		}

		/// <summary>
		/// 字符串宽度
		/// </summary>
		/// <param name="s"></param>
		/// <param name="fontSize"></param>
		/// <returns></returns>
		public static float StringWidth(this string s, int fontSize = 1)
		{
			var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == "Microsoft YaHei UI");
			if (fontFamily == default)
			{
				fontFamily = SystemFonts.Families.FirstOrDefault();
			}

			return TextMeasurer.MeasureSize(s, new TextOptions(fontFamily.CreateFont(fontSize))).Width;
		}

		/// <summary>
		/// 字符串宽度
		/// </summary>
		/// <param name="s"></param>
		/// <param name="fontName">字体名字，如：Microsoft YaHei UI</param>
		/// <param name="fontSize"></param>
		/// <returns></returns>
		public static float StringWidth(this string s, string fontName, int fontSize = 1)
		{
			var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == fontName);
			if (fontFamily == default)
			{
				throw new ArgumentException($"字体 {fontName} 不存在，请尝试其它字体！");
			}

			return TextMeasurer.MeasureSize(s, new TextOptions(fontFamily.CreateFont(fontSize))).Width;
		}
	}
}
